package cn.lm.activit.module.multi.instance.cmd;

import org.activiti.bpmn.model.Activity;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.MultiInstanceLoopCharacteristics;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.deploy.DeploymentManager;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.util.Activiti5Util;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;

/**
 * @author lm_jcf
 * @date 2019/5/20 16:36
 */
// 减签
public class DeleteMultiInstanceExecutionCmd implements Command<Void>, Serializable {

    protected final String NUMBER_OF_INSTANCES = "nrOfInstances";
    protected final String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
    protected final String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
    protected String collectionElementIndexVariable = "loopCounter";

    private String executionId;

    private boolean executionICompleted;

    private String taskId;

    public DeleteMultiInstanceExecutionCmd(String executionId, boolean executionICompleted, String taskId) {
        this.executionId = executionId;
        this.executionICompleted = executionICompleted;
        this.taskId = taskId;
    }

    @Override
    public Void execute(CommandContext commandContext) {

        // 获取执行实例管理器
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();

        // 获取执行实例 三级树
        ExecutionEntity executionEntity = executionEntityManager.findById(executionId);

        String processDefinitionId = executionEntity.getProcessDefinitionId();

        // 获取当前实例中的数据，因为需要判断是否是多实例任务节点
        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);

        Activity activity = (Activity) bpmnModel.getFlowElement(executionEntity.getCurrentActivityId());

        MultiInstanceLoopCharacteristics loopCharacteristics = activity.getLoopCharacteristics();
        if (loopCharacteristics == null) {
            throw new RuntimeException("没有找到 MultiInstanceLoopCharacteristics");
        }

        // 判断是否是多实例节点
        if (!(activity.getBehavior() instanceof MultiInstanceActivityBehavior)) {
            throw new RuntimeException("这个节点不是多实例节点");
        }

        DeploymentManager deploymentManager = commandContext.getProcessEngineConfiguration().getDeploymentManager();
        ProcessDefinition processDefinition = null;
        if (processDefinitionId != null) {
            processDefinition = deploymentManager.findDeployedProcessDefinitionById(processDefinitionId);
            if (processDefinition == null) {
                throw new RuntimeException("找不到流程定义");
            }
        }

        if (Activiti5Util.isActiviti5ProcessDefinition(commandContext, processDefinition)) {
            throw new RuntimeException("当前的减签类不支持5版本");
        }

        // 获取执行实例 二级树
        ExecutionEntity secondExecution = executionEntity.getParent();

        // 通过二级树 删除三级树以及关联的数据
        if (!loopCharacteristics.isSequential()) {

            executionEntityManager.deleteChildExecutions(executionEntity, "delete", false);
            executionEntityManager.deleteExecutionAndRelatedData(executionEntity, "delete", true);
        }
        if (StringUtils.isNotBlank(taskId)) {
            commandContext.getTaskEntityManager().delete(taskId);
        }

        // 更新变量表数据

        int loopCounter = 0;
        if (loopCharacteristics.isSequential()) {
            // 串行多实例
            loopCounter = this.getLoopVariable(executionEntity, collectionElementIndexVariable);
        }else {
            // 并行
            Integer variable = (Integer) secondExecution.getVariable(NUMBER_OF_ACTIVE_INSTANCES);
            secondExecution.setVariableLocal(NUMBER_OF_ACTIVE_INSTANCES, variable - 1);
        }

        if (executionICompleted) {
            Integer variable = (Integer) secondExecution.getVariable(NUMBER_OF_COMPLETED_INSTANCES);
            secondExecution.setVariableLocal(NUMBER_OF_COMPLETED_INSTANCES, variable + 1);
            loopCounter++;
            executionEntity.setVariableLocal(collectionElementIndexVariable,loopCounter);
        }else {
            Integer variable = (Integer) secondExecution.getVariable(NUMBER_OF_INSTANCES);
            secondExecution.setVariableLocal(NUMBER_OF_INSTANCES, variable - 1);
        }

        // 触发实例运转
        commandContext.getAgenda().planContinueProcessInCompensation(executionEntity);

        return null;
    }

    protected Integer getLoopVariable(DelegateExecution execution, String variableName) {
        Object value = execution.getVariableLocal(variableName);
        DelegateExecution parent = execution.getParent();
        while (value == null && parent != null) {
            value = parent.getVariableLocal(variableName);
            parent = parent.getParent();
        }
        return (Integer) (value != null ? value : 0);
    }

}
